diff options
Diffstat (limited to 'app/[lng]/partners')
18 files changed, 196 insertions, 54 deletions
diff --git a/app/[lng]/partners/(partners)/basic-contract/page.tsx b/app/[lng]/partners/(partners)/basic-contract/page.tsx index 5316c357..37b7d1a6 100644 --- a/app/[lng]/partners/(partners)/basic-contract/page.tsx +++ b/app/[lng]/partners/(partners)/basic-contract/page.tsx @@ -45,7 +45,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight">
기본계약서 서명 요청현황
</h2>
- <InformationButton pageCode="partners/basic-contract" />
+ <InformationButton pagePath="partners/basic-contract" />
</div>
<p className="text-muted-foreground">
기본계약서를 비롯하여 초기 서명이 필요한 문서의 서명 현황을 확인할 수 있고 서명을 진행할 수 있습니다. {" "}
diff --git a/app/[lng]/partners/(partners)/cbe-tech/page.tsx b/app/[lng]/partners/(partners)/cbe-tech/page.tsx index 9aeb4e66..35d7bba4 100644 --- a/app/[lng]/partners/(partners)/cbe-tech/page.tsx +++ b/app/[lng]/partners/(partners)/cbe-tech/page.tsx @@ -54,7 +54,7 @@ export default async function CBEPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> Commercial Bid Evaluation </h2> - <InformationButton pageCode="partners/cbe-tech" /> + <InformationButton pagePath="partners/cbe-tech" /> </div> <p className="text-sm text-muted-foreground"> CBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "} diff --git a/app/[lng]/partners/(partners)/cbe/page.tsx b/app/[lng]/partners/(partners)/cbe/page.tsx index 235426a4..01393551 100644 --- a/app/[lng]/partners/(partners)/cbe/page.tsx +++ b/app/[lng]/partners/(partners)/cbe/page.tsx @@ -54,7 +54,7 @@ export default async function CBEPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> Commercial Bid Evaluation </h2> - <InformationButton pageCode="partners/cbe" /> + <InformationButton pagePath="partners/cbe" /> </div> <p className="text-sm text-muted-foreground"> CBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "} diff --git a/app/[lng]/partners/(partners)/dashboard/page.tsx b/app/[lng]/partners/(partners)/dashboard/page.tsx index 01d3c2be..71b70abc 100644 --- a/app/[lng]/partners/(partners)/dashboard/page.tsx +++ b/app/[lng]/partners/(partners)/dashboard/page.tsx @@ -1,50 +1,126 @@ -import * as React from "react" -import { Skeleton } from "@/components/ui/skeleton" -import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" -import { Shell } from "@/components/shell" -import { InformationButton } from "@/components/information/information-button" +// app/procurement/dashboard/page.tsx +import * as React from "react"; +import { Skeleton } from "@/components/ui/skeleton"; +import { Shell } from "@/components/shell"; +import { DashboardClient } from "@/lib/dashboard/dashboard-client"; +import { getPartnersDashboardData } from "@/lib/dashboard/partners-service"; -export default async function IndexPage() { +// 대시보드 데이터 로딩 컴포넌트 +async function DashboardContent() { + try { + const data = await getPartnersDashboardData("partners"); + + const handleRefresh = async () => { + "use server"; + return await getPartnersDashboardData("partners"); + }; + return ( + <DashboardClient + initialData={data} + onRefresh={handleRefresh} + /> + ); + } catch (error) { + console.error("Dashboard data loading error:", error); + throw error; + } +} +// 대시보드 로딩 스켈레톤 +function DashboardSkeleton() { return ( - <Shell className="gap-2"> + <div className="space-y-6"> + {/* 헤더 스켈레톤 */} <div className="flex items-center justify-between"> - <div> - <div className="flex items-center gap-2"> - <h2 className="text-2xl font-bold tracking-tight"> - Dashboard - </h2> - <InformationButton pageCode="partners/dashboard" /> + <div className="space-y-2"> + <Skeleton className="h-8 w-48" /> + <Skeleton className="h-4 w-72" /> + </div> + <Skeleton className="h-10 w-24" /> + </div> + + {/* 요약 카드 스켈레톤 */} + <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"> + {[...Array(4)].map((_, i) => ( + <div key={i} className="space-y-3 p-6 border rounded-lg"> + <div className="flex items-center justify-between"> + <Skeleton className="h-4 w-16" /> + <Skeleton className="h-4 w-4" /> + </div> + <Skeleton className="h-8 w-12" /> + <Skeleton className="h-3 w-20" /> + </div> + ))} + </div> + + {/* 차트 스켈레톤 */} + <div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> + {[...Array(2)].map((_, i) => ( + <div key={i} className="space-y-4 p-6 border rounded-lg"> + <div className="space-y-2"> + <Skeleton className="h-6 w-32" /> + <Skeleton className="h-4 w-48" /> + </div> + <Skeleton className="h-[300px] w-full" /> </div> - <p className="text-muted-foreground"> - 각종 지표 등을 대시보드로 표현하거나 리포트를 출력할 수 있습니다. - </p> + ))} + </div> + + {/* 탭 스켈레톤 */} + <div className="space-y-4"> + <Skeleton className="h-10 w-64" /> + <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3"> + {[...Array(6)].map((_, i) => ( + <div key={i} className="space-y-4 p-6 border rounded-lg"> + <Skeleton className="h-6 w-32" /> + <div className="space-y-3"> + <div className="flex justify-between"> + <Skeleton className="h-4 w-16" /> + <Skeleton className="h-4 w-12" /> + </div> + <div className="flex gap-2"> + <Skeleton className="h-6 w-16" /> + <Skeleton className="h-6 w-16" /> + <Skeleton className="h-6 w-16" /> + </div> + <Skeleton className="h-2 w-full" /> + </div> + </div> + ))} </div> </div> + </div> + ); +} - <React.Suspense fallback={<Skeleton className="h-7 w-52" />}> - {/* <DateRangePicker - triggerSize="sm" - triggerClassName="ml-auto w-56 sm:w-60" - align="end" - shallow={false} - /> */} - </React.Suspense> - - <React.Suspense - fallback={ - <DataTableSkeleton - columnCount={6} - searchableColumnCount={1} - filterableColumnCount={2} - cellWidths={["10rem", "40rem", "12rem", "12rem", "8rem", "8rem"]} - shrinkZero - /> - } +// 에러 표시 컴포넌트 +function DashboardError({ error, reset }: { error: Error; reset: () => void }) { + return ( + <div className="flex flex-col items-center justify-center py-12 space-y-4"> + <div className="text-center space-y-2"> + <h3 className="text-lg font-semibold">대시보드를 불러올 수 없습니다</h3> + <p className="text-muted-foreground"> + {error.message || "알 수 없는 오류가 발생했습니다."} + </p> + </div> + <button + onClick={reset} + className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90" > - </React.Suspense> + 다시 시도 + </button> + </div> + ); +} + +export default async function DashboardPage() { + return ( + <Shell className="gap-6"> + <React.Suspense fallback={<DashboardSkeleton />}> + <DashboardContent /> + </React.Suspense> </Shell> - ) -}
\ No newline at end of file + ); +} diff --git a/app/[lng]/partners/(partners)/document-list-ship/page.tsx b/app/[lng]/partners/(partners)/document-list-ship/page.tsx index da4d9e90..f6ceb264 100644 --- a/app/[lng]/partners/(partners)/document-list-ship/page.tsx +++ b/app/[lng]/partners/(partners)/document-list-ship/page.tsx @@ -36,7 +36,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> Document Management </h2> - <InformationButton pageCode="partners/document-list-ship" /> + <InformationButton pagePath="partners/document-list-ship" /> </div> <p className="text-muted-foreground"> 소속 회사의 모든 도서/도면을 확인하고 관리합니다. diff --git a/app/[lng]/partners/(partners)/evaluation/page.tsx b/app/[lng]/partners/(partners)/evaluation/page.tsx index 2ddaf365..085b3d65 100644 --- a/app/[lng]/partners/(partners)/evaluation/page.tsx +++ b/app/[lng]/partners/(partners)/evaluation/page.tsx @@ -36,7 +36,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> 정기평가 </h2> - <InformationButton pageCode="partners/evaluation" /> + <InformationButton pagePath="partners/evaluation" /> </div> <p className="text-muted-foreground"> 요청된 정기평가를 입력하고 제출할 수 있습니다. diff --git a/app/[lng]/partners/(partners)/qna/page.tsx b/app/[lng]/partners/(partners)/qna/page.tsx new file mode 100644 index 00000000..bdd1372d --- /dev/null +++ b/app/[lng]/partners/(partners)/qna/page.tsx @@ -0,0 +1,66 @@ +import * as React from "react" +import { type SearchParams } from "@/types/table" + +import { getValidFilters } from "@/lib/data-table" +import { Skeleton } from "@/components/ui/skeleton" +import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" +import { DateRangePicker } from "@/components/date-range-picker" +import { Shell } from "@/components/shell" + +import { FeatureFlagsProvider } from "@/lib/tasks/table/feature-flags-provider" +import { QnaTable } from "@/lib/qna/table/qna-table" +import { getQnaList } from "@/lib/qna/service" +import { searchParamsQnaCache } from "@/lib/qna/validation" + +interface IndexPageProps { + searchParams: Promise<SearchParams> +} + +export default async function IndexPage(props: IndexPageProps) { + const searchParams = await props.searchParams + const search = searchParamsQnaCache.parse(searchParams) + + const validFilters = getValidFilters(search.filters) + + const promises = Promise.all([ + getQnaList({ + ...search, + filters: validFilters, + }), + ]) + + return ( + <Shell className="gap-2"> + <div className="flex items-center justify-between space-y-2"> + <div className="flex items-center justify-between space-y-2"> + <div> + <div className="flex items-center gap-2"> + <h2 className="text-2xl font-bold tracking-tight"> + Q&A + </h2> + </div> + <p className="text-muted-foreground"> + 협력업체로부터 수집된 질문에 대해서 댓글을 달거나 응답할 수 있습니다. + </p> + </div> + </div> + + </div> + <React.Suspense fallback={<Skeleton className="h-7 w-52" />}> + </React.Suspense> + <React.Suspense + fallback={ + <DataTableSkeleton + columnCount={6} + searchableColumnCount={1} + filterableColumnCount={2} + cellWidths={["10rem", "40rem", "12rem", "12rem", "8rem", "8rem"]} + shrinkZero + /> + } + > + <QnaTable promises={promises} domain={"partners"} /> + </React.Suspense> + </Shell> + ) +} diff --git a/app/[lng]/partners/(partners)/rfq-answer/page.tsx b/app/[lng]/partners/(partners)/rfq-answer/page.tsx index 7a5dabd9..9037062f 100644 --- a/app/[lng]/partners/(partners)/rfq-answer/page.tsx +++ b/app/[lng]/partners/(partners)/rfq-answer/page.tsx @@ -42,7 +42,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> 응답 관리 </h2> - <InformationButton pageCode="partners/rfq-answer" /> + <InformationButton pagePath="partners/rfq-answer" /> </div> <p className="text-muted-foreground"> RFQ 첨부파일 응답 현황을 확인하고 관리합니다. diff --git a/app/[lng]/partners/(partners)/rfq-ship/page.tsx b/app/[lng]/partners/(partners)/rfq-ship/page.tsx index 1ad7cfe8..fbad280a 100644 --- a/app/[lng]/partners/(partners)/rfq-ship/page.tsx +++ b/app/[lng]/partners/(partners)/rfq-ship/page.tsx @@ -42,7 +42,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> 견적 목록 </h2> - <InformationButton pageCode="partners/rfq-ship" /> + <InformationButton pagePath="partners/rfq-ship" /> </div> <p className="text-muted-foreground"> 진행 중인 견적서 목록을 확인하고 관리합니다. diff --git a/app/[lng]/partners/(partners)/rfq-tech/page.tsx b/app/[lng]/partners/(partners)/rfq-tech/page.tsx index a196cf9e..154247fe 100644 --- a/app/[lng]/partners/(partners)/rfq-tech/page.tsx +++ b/app/[lng]/partners/(partners)/rfq-tech/page.tsx @@ -36,7 +36,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> RFQ </h2> - <InformationButton pageCode="partners/rfq-tech" /> + <InformationButton pagePath="partners/rfq-tech" /> </div> <p className="text-muted-foreground"> RFQ를 응답하고 커뮤니케이션을 할 수 있습니다. diff --git a/app/[lng]/partners/(partners)/rfq/page.tsx b/app/[lng]/partners/(partners)/rfq/page.tsx index 612d48f5..87202155 100644 --- a/app/[lng]/partners/(partners)/rfq/page.tsx +++ b/app/[lng]/partners/(partners)/rfq/page.tsx @@ -105,7 +105,7 @@ export default async function IndexPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> RFQ </h2> - <InformationButton pageCode="partners/rfq" /> + <InformationButton pagePath="partners/rfq" /> </div> <p className="text-muted-foreground"> RFQ를 응답하고 커뮤니케이션을 할 수 있습니다. diff --git a/app/[lng]/partners/(partners)/tbe-tech/page.tsx b/app/[lng]/partners/(partners)/tbe-tech/page.tsx index 463a8dc9..2085ca36 100644 --- a/app/[lng]/partners/(partners)/tbe-tech/page.tsx +++ b/app/[lng]/partners/(partners)/tbe-tech/page.tsx @@ -53,7 +53,7 @@ export default async function RfqTBEPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> Technical Bid Evaluation </h2> - <InformationButton pageCode="partners/tbe-tech" /> + <InformationButton pagePath="partners/tbe-tech" /> </div> <p className="text-sm text-muted-foreground"> TBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "} diff --git a/app/[lng]/partners/(partners)/tbe/page.tsx b/app/[lng]/partners/(partners)/tbe/page.tsx index b85ebf71..96f42e09 100644 --- a/app/[lng]/partners/(partners)/tbe/page.tsx +++ b/app/[lng]/partners/(partners)/tbe/page.tsx @@ -53,7 +53,7 @@ export default async function RfqTBEPage(props: IndexPageProps) { <h2 className="text-2xl font-bold tracking-tight"> Technical Bid Evaluation </h2> - <InformationButton pageCode="partners/tbe" /> + <InformationButton pagePath="partners/tbe" /> </div> <p className="text-sm text-muted-foreground"> TBE에 응답하고 커뮤니케이션을 할 수 있습니다.{" "} diff --git a/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx b/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx index 0504b51b..0325130e 100644 --- a/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx +++ b/app/[lng]/partners/(partners)/techsales/rfq-offshore-hull/page.tsx @@ -63,7 +63,7 @@ export default async function VendorQuotationsHullPage() { <div> <div className="flex items-center gap-2"> <h1 className="text-3xl font-bold tracking-tight">기술영업 해양HULL 견적서</h1> - <InformationButton pageCode="partners/techsales/rfq-offshore-hull" /> + <InformationButton pagePath="partners/techsales/rfq-offshore-hull" /> </div> <p className="text-muted-foreground"> 할당받은 해양HULL RFQ에 대한 견적서를 작성하고 관리합니다. diff --git a/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx b/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx index b872058f..6c3eaf56 100644 --- a/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx +++ b/app/[lng]/partners/(partners)/techsales/rfq-offshore-top/page.tsx @@ -65,7 +65,7 @@ export default async function VendorQuotationsTopPage() { <div> <div className="flex items-center gap-2"> <h1 className="text-3xl font-bold tracking-tight">기술영업 해양TOP 견적서</h1> - <InformationButton pageCode="partners/techsales/rfq-offshore-top" /> + <InformationButton pagePath="partners/techsales/rfq-offshore-top" /> </div> <p className="text-muted-foreground"> 할당받은 해양TOP RFQ에 대한 견적서를 작성하고 관리합니다. diff --git a/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx b/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx index ad2ab07b..68830184 100644 --- a/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx +++ b/app/[lng]/partners/(partners)/techsales/rfq-ship/page.tsx @@ -68,7 +68,7 @@ export default async function VendorQuotationsPage() { <div> <div className="flex items-center gap-2"> <h1 className="text-3xl font-bold tracking-tight">기술영업 조선 견적서</h1> - <InformationButton pageCode="partners/techsales/rfq-ship" /> + <InformationButton pagePath="partners/techsales/rfq-ship" /> </div> <p className="text-muted-foreground"> 할당받은 조선 RFQ에 대한 견적서를 작성하고 관리합니다. diff --git a/app/[lng]/partners/(partners)/vendor-data/layout.tsx b/app/[lng]/partners/(partners)/vendor-data/layout.tsx index bdf352c7..cf658e80 100644 --- a/app/[lng]/partners/(partners)/vendor-data/layout.tsx +++ b/app/[lng]/partners/(partners)/vendor-data/layout.tsx @@ -41,7 +41,7 @@ export default async function VendorDataLayout({ <h2 className="text-2xl font-bold tracking-tight"> Vendor Data </h2> - <InformationButton pageCode="partners/vendor-data" /> + <InformationButton pagePath="partners/vendor-data" /> </div> <p className="text-muted-foreground"> 각종 Data 입력할 수 있습니다 diff --git a/app/[lng]/partners/pq_new/page.tsx b/app/[lng]/partners/pq_new/page.tsx index 24051f34..f822eacc 100644 --- a/app/[lng]/partners/pq_new/page.tsx +++ b/app/[lng]/partners/pq_new/page.tsx @@ -133,7 +133,7 @@ export default async function PQListPage() { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight">사전 평가 (PQ) 목록</h2> - <InformationButton pageCode="partners/pq_new" /> + <InformationButton pagePath="partners/pq_new" /> </div> <p className="text-muted-foreground"> 요청된 사전 평가 목록을 확인하고 작성합니다. |
